package cn.jeeweb.web.modules.sys.service.impl;

import cn.jeeweb.common.annotate.UiPropertyField;
import cn.jeeweb.common.mybatis.mvc.service.impl.CommonServiceImpl;
import cn.jeeweb.common.mybatis.mvc.wrapper.EntityWrapper;
import cn.jeeweb.common.utils.StringUtils;
import cn.jeeweb.web.modules.sys.entity.UiPackageInfo;
import cn.jeeweb.web.modules.sys.entity.UiProperty;
import cn.jeeweb.web.modules.sys.mapper.UiPropertyMapper;
import cn.jeeweb.web.modules.sys.service.IUiPackageInfoService;
import cn.jeeweb.web.modules.sys.service.IUiPropertyService;
import cn.xjzn.framework_Core.ControlType;
import cn.xjzn.framework_Core.DataType;
import cn.xjzn.framework_Core.ModuleServe;
import cn.xjzn.framework_Core.StaticControl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;


/**
* @description: ui_property服务实现
*/
@Transactional
@Service("uiPropertyService")
public class UiPropertyServiceImpl extends CommonServiceImpl<UiPropertyMapper,UiProperty> implements IUiPropertyService {

    @Autowired
    private IUiPackageInfoService uiPackageInfoService;

    @Override
    public List<UiProperty> getList(UiProperty uiProperty) {
        return baseMapper.getList(uiProperty);
    }


    /**
     * 从字段里解析出UiProperty配置信息
     * @param field
     * @return
     */
    private static UiProperty getFromAnnotation(Field field)
    {
        UiPropertyField annotation_ = field.getAnnotation(UiPropertyField.class);
        UiProperty u=getFromAnnotation(annotation_);
        if(StringUtils.isEmpty(annotation_.propertyName()+annotation_.aliasName()))
            u.setPropertyName(field.getName());
        return u;
    }

    /**
     * 从注解配置，提取为配置数据
     * @param a
     * @return
     */
    private static UiProperty getFromAnnotation(UiPropertyField a)
    {
        UiProperty p=new UiProperty();
        ModuleServe moduleId=a.moduleId();
        p.setModuleId(moduleId.getValue());

        String propertyName=a.propertyName();
        p.setPropertyName(propertyName);

        p.setAliasName(a.aliasName());

        String labelText=a.labelText();
        p.setLabelText(labelText);

        String ownerPropertyName=a.ownerPropertyName();
        p.setOwnerPropertyName(ownerPropertyName);

        ControlType controlType=a.controlType();
        p.setControlType(controlType.getValue());

        StaticControl staticControl=a.staticControl();
        p.setStaticControl(staticControl.getValue());

        DataType dataType=a.dataType();
        p.setDataType(dataType.getValue());
        int isReference=a.isReference();
        p.setIsReference(isReference);
        //String referenceClass() default "";
        ModuleServe referenceModuleId=a.referenceModuleId();
        p.setReferenceModuleId(referenceModuleId.getValue());

        /** 数据字典组Code，当controlType为1时，必填 */
        String dictCode=a.dictCode();
        p.setDictCode(dictCode);

        /** 显示位置，值越小位置越靠前 */
        int displayPosition=a.displayPosition();
        p.setDisplayPosition(displayPosition);
        /** 是否可显示 */
        boolean canDisplay=a.canDisplay();
        p.setCanDisplay(canDisplay?1:0);
        /** 是否能用于查询 */
        boolean canSearch=a.canSearch();
        p.setCanSearch(canSearch?1:0);
        /** 在查询结果界面是否显示 */
        boolean isDisplayAsSearchResult=a.isDisplayAsSearchResult();
        p.setIsDisplayAsSearchResult(isDisplayAsSearchResult?1:0);
        /** 是否可为空值 */
        boolean canBeNull=a.canBeNull();
        p.setCanBeNull(canBeNull?1:0);
        /** 是否只读 */
        boolean isReadOnly=a.isReadOnly();
        p.setIsReadOnly(isReadOnly?1:0);
        /** 是否允许修改（针对只读的字段，新建时可编辑。） */
        boolean isSupportNewEdit=a.isSupportNewEdit();
        p.setIsSupportNewEdit(isSupportNewEdit?1:0);
        /** 是否允许变更 */
        boolean isSupportModify=a.isSupportModify();
        p.setIsSupportModify(isSupportModify?1:0);
        /** 字符或者数字的最大长度 */
        int dataSize=a.dataSize();
        p.setDataSize(dataSize);
        /** 实数的精度 */
        int dataPrecision=a.dataPrecision();
        p.setDataPrecision(dataPrecision);
        /** 应用规则的Code：多个以|连接 */
        String controlRule=a.controlRule();
        p.setControlRule(controlRule);
        /** 是否需要显示标签 */
        boolean withLabel=a.withLabel();
        p.setWithLabel(withLabel?1:0);
        /** 控件是否独占一行 */
        boolean isSingleRow=a.isSingleRow();
        p.setIsSingleRow(isSingleRow?1:0);
        /** 控件宽度 */
        String width=a.width();
        p.setWidth(width);
        /** 能否打印 */
        boolean canPrint=a.canPrint();
        p.setCanPrint(canPrint?1:0);
        /** 能否导出 */
        boolean canExport=a.canExport();
        p.setCanExport(canExport?1:0);
        return p;
    }

    @Override
    public List<UiProperty> getUiPropertiesFromDB(String...packageIds)
    {
        EntityWrapper<UiProperty> entityWrapper = new EntityWrapper<>(UiProperty.class);
            entityWrapper.in("packageId", packageIds);
        return selectList(entityWrapper);
    }

    /**
     * 根据类定义，获取字段清单,会根据继承递归获取父类字段
     * @param clazz
     * @return
     */
    private void getFields(Class<?> clazz,List<Field> rets){
        if(clazz!=null) {
            Field[] declaredFields = clazz.getDeclaredFields();
            if (declaredFields.length > 0)
                Collections.addAll(rets, declaredFields);
            Class<?> superClazz = clazz.getSuperclass();
            if (superClazz != null)
                getFields(superClazz, rets);
        }
    }

    private List<UiPropertyField> getUiPropertyFields(List<Field> fields){
        List<UiPropertyField> rets=new ArrayList<>();
        fields.forEach(t->{
            if(t.isAnnotationPresent(UiPropertyField.class)) {
                UiPropertyField annotation = t.getAnnotation(UiPropertyField.class);
                rets.add(annotation);
            }
        });
        rets.sort(Comparator.comparing(UiPropertyField::displayPosition));
        return rets;
    }

    /**
     * 根据字段注释描述，转为自定义类描述
     * @param fields 入参，字段集合
     * @param actualTypeFromLists 出参，顺带记录下：针对List<E>对象的实体类的Map
     * @return
     */
    private List<UiPropertyField> getUiPropertyFields(List<Field> fields,Map<String,Class<?>> actualTypeFromLists){
        List<UiPropertyField> rets=new ArrayList<>();
        fields.forEach(t->{
            if(t.isAnnotationPresent(UiPropertyField.class)) {
                UiPropertyField annotation = t.getAnnotation(UiPropertyField.class);
                rets.add(annotation);
            }

            //取List<E>对象的实际类名
            t.setAccessible(true);
            if(t.getType() == java.util.List.class){
                // 如果是List类型，得到其Generic的类型
                Type genericType = t.getGenericType();
                // 如果是泛型参数的类型
                if(genericType instanceof ParameterizedType){
                    ParameterizedType pt = (ParameterizedType) genericType;
                    //得到泛型里的class类型对象
                    Class<?> genericClazz = (Class<?>)pt.getActualTypeArguments()[0];
                    if(genericClazz!=null)
                        actualTypeFromLists.put(t.getName(),genericClazz);
                }
            }
        });
        rets.sort(Comparator.comparing(UiPropertyField::displayPosition));
        return rets;
    }

    @Override
    public List<UiProperty> getUiPropertiesFromEntity(String packageId){
        UiPackageInfo uiPackageInfo=uiPackageInfoService.selectById(packageId);
        String propertyNameForPackage=uiPackageInfo.getPropertyName();
        boolean isGetSubDataPropertys= !StringUtils.isEmpty(propertyNameForPackage);
        List<UiProperty> uiProperties = new ArrayList<UiProperty>();
        String moduleId=uiPackageInfo.getModuleId();
        ModuleServe moduleServe = ModuleServe.getEnumByValue(moduleId);
        if ("-1".equals(moduleServe.getValue())) {
            return uiProperties;
        }
        try {
            String entityName = moduleServe.getEntityName();
            Class<?> clazz = Class.forName(entityName);
            ArrayList<Field> fields= new ArrayList<>();
            getFields(clazz,fields);

            if(fields.size() > 0){
                int isReference = 0;
                String ownerPropertyName="";
                AtomicInteger dispPositionIndex= new AtomicInteger();
                Map<String,Class<?>> actualTypeFromLists=new HashMap<>();
                List<UiPropertyField> uiPropertyFields=getUiPropertyFields(fields,actualTypeFromLists);
                if(isGetSubDataPropertys)
                    uiPropertyFields.removeIf(t->t.dataType()!=DataType.SUBLISTDATATYPE || !t.propertyName().equals(propertyNameForPackage));
                else
                    uiPropertyFields.removeIf(t->t.dataType()==DataType.SUBLISTDATATYPE);

                for(UiPropertyField annotation : uiPropertyFields) {
                    UiProperty uiProperty = null;
                    List<UiProperty> child = new ArrayList<UiProperty>();
                    List<UiProperty> reference = new ArrayList<UiProperty>();

                    isReference = annotation.isReference();
                    ownerPropertyName = annotation.ownerPropertyName();
                    uiProperty = getFromAnnotation(annotation);
                    uiProperty.setModuleId(moduleId);
                    uiProperty.setDisplayPosition(dispPositionIndex.get());
                    dispPositionIndex.addAndGet(10);
                    if (DataType.SUBLISTDATATYPE.getValue() == uiProperty.getDataType()) {
                        String name_= uiProperty.getAliasName();
                        if(StringUtils.isEmpty(name_))
                            name_=uiProperty.getPropertyName();
                        Class<?> claz=actualTypeFromLists.get(name_);
                        ArrayList<Field> childFields = new ArrayList<>();
                        getFields(claz, childFields);

                        childFields.forEach(t -> {
                            if (t.isAnnotationPresent(UiPropertyField.class)) {
                                UiProperty u = getFromAnnotation(t);
                                u.setModuleId(moduleId);
                                child.add(u);
                            }
                        });
                    }
                    if (isReference == 1) {
                        //字段自身的处理
                        uiProperty.setOwnerPropertyName(ownerPropertyName);
                        uiProperty.setCanDisplay(0);
                        uiProperty.setIsDisplayAsSearchResult(0);
                        uiProperty.setCanSearch(0);
                        uiProperty.setIsSupportNewEdit(0);

                        //引用对象的字段的处理
                        Optional<Field> found = Optional.empty();
                        for (Field t1 : fields) {
                            if (t1.getName().equals(ownerPropertyName)) {
                                found = Optional.of(t1);
                                break;
                            }
                        }
                        if (found.isPresent()) {

                            String referenceModuleId = uiProperty.getReferenceModuleId();

                            //引用对象的字段的处理
                            Field found_ = found.get();
                            Class<?> claz = found_.getType();
                            ArrayList<Field> referenceFields = new ArrayList<>();
                            getFields(claz, referenceFields);

                            String finalOwnerPropertyName = ownerPropertyName;

                            List<UiPropertyField> refUiPropertyFields=getUiPropertyFields(referenceFields);
                            refUiPropertyFields.forEach(r -> {
                                UiProperty u = getFromAnnotation(r);
                                u.setModuleId(moduleId);

                                String aliseName = u.getPropertyName() + "@" + finalOwnerPropertyName;

                                //引用数据，只做显示，所以初始设置如下 ：
                                if ("CODE,NAME,FULLNAME".contains(u.getPropertyName().toUpperCase())) {
                                    u.setCanDisplay(1);  //表单 显示
                                    u.setIsDisplayAsSearchResult(1);  //列表 显示
                                } else {
                                    u.setCanDisplay(0);
                                    u.setIsDisplayAsSearchResult(0);
                                }
                                u.setCanSearch(0);
                                u.setIsReadOnly(1);
                                u.setIsSupportNewEdit(0);
                                u.setIsReference(1);
                                u.setReferenceModuleId(referenceModuleId);
                                u.setAliasName(aliseName);
                                u.setOwnerPropertyName(finalOwnerPropertyName);
                                u.setDisplayPosition(dispPositionIndex.get());
                                dispPositionIndex.addAndGet(10);

                                reference.add(u);
                            });
                        }
                    }
//                    if (child.size() > 0) {
//                        uiProperty.setChildUiProperty(child);
//                    }

                    if(isGetSubDataPropertys) {
                        if (child.size() > 0)
                            uiProperties = child;  //todo:临时child对象的层级。应该是同级，独立处理，子数据配置属性里边应该还有引用的数据 byAkin 20191119
                    }
                    else {
                        if (reference.size() > 0) {
                            uiProperty.setReferenceUiProperty(reference);
                        }
                        uiProperties.add(uiProperty);
                    }
                }
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        return uiProperties;
    }
}